﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace Nes.Core.Mappers
{
    public static class MapperUtil
    {
        public static IMapper CreateMapper(ICartridge cartridge, Byte[] sram)
        {
            switch (cartridge.HeaderInfo.Mapper)
            {
                case 0:
                    return new Mapper0(cartridge, sram);
                case 3:
                    return new Mapper3(cartridge, sram);
                default:
                    throw new NotImplementedException($"不支持的Mapper {cartridge.HeaderInfo.Mapper}");
            }
        }
    }

    public class Mapper0 : IMapper
    {
        public ICartridge cartridge { get; private set; }
        /// <summary>
        /// 程序数据 [0x8000, 0xffff) 32KB
        /// </summary>
        public Byte[] PRG { get; private set; }
        /// <summary>
        /// 图像数据 [0x0000, 0x2000) 8KB
        /// </summary>
        public Byte[] CHR { get; private set; }
        /// <summary>
        /// 扩展的内存 [0x6000,0x8000) 8KB
        /// </summary>
        public Byte[] SRAM { get; private set; }

        public Boolean IsMirrored { get; private set; }

        public Mapper0(ICartridge cartridge, Byte[] sram)
        {
            this.cartridge = cartridge;
            this.PRG = cartridge.PRG;
            this.CHR = cartridge.CHR;
            this.IsMirrored = PRG.Length == 16 * 1024;
            if(sram.Length == 0)
            {
                SRAM = new Byte[0x2000];
            }
        }

        public Byte Read(Int32 addr)
        {
            var address = addr & 0xFFFF;
            if (address < 0x2000)
            {
                return this.CHR[address];
            }
            else if (address >= 0x8000)
            {
                // this.isMirrored ? address & 0xBFFF : address) - 0x8000
                return this.PRG[ParseAddr(address)];
            }
            else if (address >= 0x6000)
            {
                return this.SRAM[address - 0x6000];
            }
            else
            {
                return 0;
            }
        }

        public void Write(Int32 addr, Byte value)
        {
            var address = addr & 0xFFFF;
            if (address < 0x2000)
            {
                this.CHR[address] = value;
            }
            else if (address >= 0x8000)
            {
                this.PRG[ParseAddr(address)] = value;
            }
            else if (address >= 0x6000)
            {
                this.SRAM[address - 0x6000] = value;
            }
        }

        private Int32 ParseAddr(Int32 addr)
        {
            return (IsMirrored ? addr & 0xBFFF : addr) - 0x8000;
        }

        public void PPUClockHandle(int scanLine, int cycle)
        {
            
        }
    }

    public enum Mirror
    {
        /// <summary>
        /// 水平
        /// Horizontal mirroring: $2000 equals $2400 and $2800 equals $2C00 (e.g. Kid Icarus)
        /// </summary>
        HORIZONTAL,
        /// <summary>
        /// 垂直
        /// Vertical mirroring: $2000 equals $2800 and $2400 equals $2C00 (e.g. Super Mario Bros.)
        /// </summary>
        VERTICAL,
        /// <summary>
        /// Four-screen mirroring: The cartridge contains additional VRAM used for all nametables (e.g. Gauntlet, Rad Racer 2)
        /// </summary>
        FOUR_SCREEN,
        // 以下很少使用
        SINGLE_SCREEN_LOWER_BANK,
        SINGLE_SCREEN_UPPER_BANK
    }
}
